package mathy.wili.extract_srcFile.java;
import java.io.File;
import java.io.FileNotFoundException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import _a.Config26;
import mathy.c.Ca;
import mathy.wili.autoeq.Refs;
import mathy.wili.c.Class9;
import mathy.wili.c.File9;
import mathy.wili.c.Misc9;
import mathy.wili.c.Src9;
import mathy.wili.c.Str9;
import mathy.wili.c.asm.Asm9;
import mathy.wili.c.asm.AsmItems.AsmItem;
import mathy.wili.codegenerator.BeanToHtml__;
public class Coms26 {
	static final String NL = Str9.NL;

	public static List<String> msgList = new ArrayList<>();
	public static boolean ref(int opt) {
		if (opt != 3)
			return true;
		return true;
	}

	public static void addMsg(int opt, Object... msgs) {
		String msg = Ca.strOfObjs(msgs);
		msgList.add(msg);
		Ca.debug(opt, msg);
	}

	/**
	 * 
	 */
	static void visit_all_simple_staticFinalField_fromImports_and_samePackage(RootOfClsMember root) {
		if ("".isEmpty())
			return;
		//做法粗暴，不可取。
		//简单静态常量值一旦被引用，就必须提取其代码。但asm找不到对它的引用，只能无条件提取。
		if (!_clsSet1.add(root.clazz))
			return;
		if (root.clazz.equals(BeanToHtml__.class))
			Ca.pause();
		List<Class<?>> ccList;
		{//搜集引入类和同包下的类
			Collection<Class<?>> cc = root.importMap.clsMap.values();
			Class<?>[] cc2 = {};
			if (_packageSet.add(root.clazz.getPackageName())) {
				cc2 = Class9.getAllClass_inPackage(root.clazz);
			}
			ccList = new ArrayList<>(cc.size() + cc2.length);
			ccList.addAll(cc);
			for (Class<?> cls : cc2) {
				if (cls.isLocalClass() || cls.isSynthetic())
					continue;
				ccList.add(cls);
			}
		}
		ccList.size();
		int times = 0;
		{//访问这些类中的静态常量简单值属性
			for (Class<?> cls : ccList) {
				if (cls == null)
					continue;
				if (!_clsSet1.add(root.clazz))
					return;
				times += Coms26.visitStaticFinalSimpleFields(cls);
			}
		}
		Integer.valueOf(times);
	}
	private static Set<Class<?>> _clsSet1 = new HashSet<>(), _clsSet2 = new HashSet<>();

	private static Set<String> _packageSet = new HashSet<>();
	/**
	 * 	读取类的属性集
	 */
	static void readClassFields(RootOfClsMember root, int fromIndex, int toIndex) {
		Refs.key();
		String fieldHead = root.fileSt0.substring(fromIndex, toIndex);
		List<Object[]> fds = Src9.readFieldRange_asList(root.fileSt, fromIndex, toIndex);
		if (fds.size() > 1)
			fds = Src9.readFieldRange_asList(root.fileSt, fromIndex, toIndex);
		FieldRange[] fields = fds.size() == 1 ? null : new FieldRange[fds.size()];
		for (int i = 0; i < fds.size(); i++) {
			Object[] fd = fds.get(i);
			int start = (Integer) fd[1], end = (Integer) fd[2];
			if (i == 0) {
				//root.fileSt0.substring(fromIndex,fromIndex+100);
				fieldHead = root.fileSt0.substring(fromIndex, start);
				//Ca.pause();
			}
			FieldRange fd2 = new FieldRange(root, fieldHead, (String) fd[0], fromIndex, start, end);
			root.memberRanges.add(fd2);
			if (fields != null) {
				fields[i] = fd2;
				fd2.ranges = fields;
			}
		}
	}

	/**
	 * 	提取父类和接口的壳子。
	 */
	static void extractShell_SuperClassAndInterfaces() {
		Set<Class<?>> clsSet = new HashSet<>(CodeExtract.DATA_MAP.keySet());
		int depth = 1;
		Refs.key();//保证提取超类和接口的壳子
		Ca.logStep("Visit super's Class shell:");
		for (Class<?> cls : clsSet) {
			Set<Class<?>> superSet = new HashSet<>();
			for (Class<?> su : cls.getInterfaces())
				superSet.add(su);
			if (cls.getSuperclass() != null)
				superSet.add(cls.getSuperclass());
			List<Class<?>> superList = new ArrayList<>(superSet);
			for (int i = 0; i < superList.size(); i++) {
				Class<?> superCls = superList.get(i);
				if (++inc == 23)
					Ca.pause();
				if (!clsSet.contains(superCls)) {
					//拷贝类结构
					RangesOfClsMember superCls2 = RangesOfClsMember.getInst(depth, superCls);
					if (superCls2 == null) {
						Ca.pause();
					} else {
						superCls2.writeMeToJavaFile();
					}
				}
				{//向上递归
					Class<?>[] faces = superCls.getInterfaces();
					for (Class<?> in : faces) {
						if (superSet.add(in))
							if (!Cont26.filesMustBeCopied.contains(in))
								superList.add(in);
					}
					Class<?> superCC = superCls.getSuperclass();
					if (superCC != null) {
						if (superSet.add(superCC))
							if (!Cont26.filesMustBeCopied.contains(superCC))
								superList.add(superCC);
					}
				}
			}
		}
	}

	/**
	 * 	如果抽象方法被访问，就得确保其子类实现该方法并深入访问之。
	 */
	public static void findImpleMethodInClass_and_deepIntoMethod(Class<?> subClass, AsmItemList toList) {
		//eg. 当提取 PutFieldFilter.doCode() 实现，若其接口 doCode()方法被访问过。
		int depth = 1;
		Refs.key();
		Method[] mm = subClass.getDeclaredMethods();
		for (Method md : mm) {
			if (Class9.isAbstractMethod(md))
				continue;
			Method abstractMethod = Class9.getAbstractMethodOf(md);
			if (abstractMethod == null)
				continue;
			RangesOfClsMember mems = RangesOfClsMember.getInst(depth, abstractMethod.getDeclaringClass());
			if (mems == null)
				continue;
			MethodRange superRange = mems.getMethodRange(abstractMethod);
			if (superRange != null && superRange.visited) {
				Visit26.visitMethod("", subClass, md);
				//new Exception("Ok, a test.").printStackTrace();
				Asm9.findInMethod_forCalledMethods_and_fields(subClass, md, null, Config26.Class_filter, toList);
			}
		}
	}

	/**
	 * 	.抽象方法是类结构的一部分，标记方法后，当随即标记其抽象方法。
	 */
	public static void visitSuperAbstractMethodOf(Method md) {//在VisitMethod.visitMethod中进行即可。
		Refs.key();
		//如果方法有多个抽象方法呢？只标记一个？
		if (md == null)
			return;
		Method abstractMethod = Class9.getAbstractMethodOf(md);
		if (abstractMethod == null)
			return;
		Ca.pause();
		Visit26.visitMethod("VisitMethod.visitAbstract:", abstractMethod.getDeclaringClass(), abstractMethod);
	}

	public static int visitStaticFinalSimpleFields(Class<?> cls) {
		if (cls == null)
			return 0;
		if (cls.isAnonymousClass())
			return 0;
		if (!cls.isInterface() && cls.isMemberClass() && !Modifier.isStatic(cls.getModifiers()))
			return 0;
		RangesOfClsMember memRange = RangesOfClsMember.getInst(-1, cls);
		if (memRange == null || memRange.root == null)
			return 0;
		int times = 0;
		for (ClsRange crange : memRange.root.getClsRangeMap().values()) {
			for (FieldRange frange : crange.fieldMap.values()) {
				if (frange.visited)
					continue;
				if (Class9.isStaticFinalSimpleValue(cls, frange.get())) {
					frange.setVisited();
					++times;
				}
			}
		}
		return times;
	}

	/**
	 * 	From AsmInitVist, can get related field information.
	 */
	static void deepVisitField_from_asmInit(AsmItem fieldRefer, AsmItemList toItemList) {
		Field field = (Field) fieldRefer.ele;
		boolean isStatic = Class9.isStaticField(field);
		Map<Class<?>, AsmItemList> infoMap = isStatic ? AsmItemList.clsToAttsInfoMap : AsmItemList.objToAttsInfoMap;
		String fname = field.getName();
		Class<?> deCls = field.getDeclaringClass();
		RangesOfClsMember ranges = RangesOfClsMember.getInst(-1, deCls);
		if (ranges == null)
			return;
		int fieldLastLineNo;
		{
			FieldRange frange = ranges.getFieldRange(deCls, fname);
			if (frange == null)
				Ca.pause();
			fieldLastLineNo = frange == null ? -1 : frange.getLastLineNo();
		}
		AsmItemList itemList = infoMap.get(deCls);
		if (itemList == null) {
			//属性初始化会有名义类型、实际类型等信息，但方法对属性的的访问只能得到名义类型
			//，当保存较多信息，直到被方法内部访问时再深入之。
			AsmItem fieldDefine = new AsmItem(null, fieldRefer.ele, fieldLastLineNo);
			itemList = new AsmItemList(fieldDefine);
			Asm9.findInInit_forCalledMethods_and_fields(//
					deCls, isStatic ? 1 : 2, null, Config26.Class_filter, itemList);
			infoMap.put(deCls, itemList);
			itemList.sort();
		}
		int j = 0, lineNo = -1;
		{//找到同名属性及其所在行
			for (; j < itemList.size(); j++) {
				AsmItem ele2 = itemList.get(j);
				if (ele2.ele instanceof Field) {
					Field fd = (Field) ele2.ele;
					if (fd.getName().equals(fname)) {
						lineNo = ele2.lineNo;
						break;
					}
				}
			}
		}
		if (lineNo == -1) {
			Ca.debug(1, "NotInit Field:" + field);
			return;
		}
		{//从属性定义行开始，到下一属性之间的元素，貌似都是属性的值表达式中的东西。当访问之。
			for (int j2 = j; j2 < itemList.size(); j2++) {
				AsmItem ele2 = itemList.get(j2);
				if (ele2.ele == field)
					continue;
				if (j2 > j) {
					if (fieldLastLineNo < 0) {
						if (ele2.ele instanceof Field) {
							if (ele2.getCls().equals(deCls)) {
								break;//遇见兄弟属性，本属性或已结束
							}
						}
					} else if (ele2.lineNo > fieldLastLineNo) {
						break;
					}
				}
				toItemList.list.add(ele2);//只对来自于方法的访问进一步深入。
			}
		}
	}

	public static void copyJavaFile(Class<?> cls) {
		String path = cls.getPackageName().replace('.', '/');
		File tofile = new File(Config26.Extract_toSourceDir, path + "/" + cls.getSimpleName() + ".java");
		File[] rr = Config26.getRootDirs_of_sourceCode();
		File[] from = File9.javafileOfClass(cls, rr);
		if (from == null) {
			new FileNotFoundException("class:" + cls + ", rootDirs:\n" + Misc9.strOfObjs("\n\t", rr)).printStackTrace();
		}
		File9.copyFile(from[1], tofile);
	}

	public static void writeVisitedClassMemberToDirectory(File toSrcRoot) {
		Ca.logStep("WriteVisitedClassMemberToDirectory:\n" + toSrcRoot.getAbsolutePath());
		toSrcRoot = Config26.Extract_toSourceDir;
		for (Class<?> cls : Cont26.filesMustBeCopied) {
			Class<?> fcls = Class9.fileClassOf(cls);
			copyJavaFile(fcls);
			++Cont26.copiedNum;
		}
		if (Boolean.FALSE && toSrcRoot.listFiles().length > 0) {
			Ca.debug(1, "失败：目录非空，无法覆写。");
			return;
		}
		CodeExtract.saveToFile = false;
		{//不能用 DATA_MAP, 因下面的visit...方法会写入Map.
			{//提取访问过的元素（属性|类型|方法）
				for (int i = 0; i < CodeExtract.DATA_LIST.size(); i++) {
					RangesOfClsMember cls2 = CodeExtract.DATA_LIST.get(i);
					if (!Cont26.filesMustBeCopied.contains(cls2.mainClass)) {
						cls2.writeMeToJavaFile();
					}
				}
			}
			if (Ca.useLog.canWarn()) {
				Ca.debug(1, "classSet:\n", Misc9.concatList(CodeExtract.DATA_MAP.keySet(), "\n"));
				Ca.debug(1, "classSet:end");
			}
		}
		{//保证祖先类被访问：拷贝必需的类结构：确保写入所有祖先类的类结构，若存在已访问过的方法，当早已被写入。
			//抽象方法是类结构的一部分, 已实现并访问过的抽象方法当早已写入。
			Coms26.extractShell_SuperClassAndInterfaces();//写父类
		}
	}
	static int inc;
}